package com.cn.appcore.utils;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.text.InputType;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;


import com.cn.appcore.config.AppConfig;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Timer;
import java.util.TimerTask;

public class KeyboardUtils {
	private static int sDecorViewInvisibleHeightPre;
	private static OnGlobalLayoutListener onGlobalLayoutListener;
	private static OnSoftInputChangedListener onSoftInputChangedListener;
	private static int sContentViewInvisibleHeightPre5497;

	private KeyboardUtils() {
		throw new UnsupportedOperationException("u can't instantiate me...");
	}

	/**
	 * Show the soft input.
	 *
	 * @param activity The activity.
	 */
	public static void showSoftInput(final Activity activity) {
		showSoftInput(activity, InputMethodManager.SHOW_FORCED);
	}

	/**
	 * Show the soft input.
	 *
	 * @param activity The activity.
	 * @param flags    Provides additional operating flags.  Currently may be
	 *                 0 or have the {@link InputMethodManager#SHOW_IMPLICIT} bit set.
	 */
	public static void showSoftInput(final Activity activity, final int flags) {
		View view = activity.getCurrentFocus();
		if (view == null) {
			view = new View(activity);
		}
		showSoftInput(view, flags);
	}

	/**
	 * Show the soft input.
	 *
	 * @param view The view.
	 */
	public static void showSoftInput(final View view) {
		showSoftInput(view, InputMethodManager.SHOW_FORCED);
	}

	/**
	 * Show the soft input.
	 *
	 * @param view  The view.
	 * @param flags Provides additional operating flags.  Currently may be
	 *              0 or have the {@link InputMethodManager#SHOW_IMPLICIT} bit set.
	 */
	public static void showSoftInput(final View view, final int flags) {
		InputMethodManager imm =
				(InputMethodManager) AppConfig.INSTANCE.getApplication().getSystemService(Context.INPUT_METHOD_SERVICE);
		if (imm == null) return;
		view.setFocusable(true);
		view.setFocusableInTouchMode(true);
		view.requestFocus();
		imm.showSoftInput(view, flags, new ResultReceiver(new Handler()) {
			@Override
			protected void onReceiveResult(int resultCode, Bundle resultData) {
				if (resultCode == InputMethodManager.RESULT_UNCHANGED_HIDDEN
						|| resultCode == InputMethodManager.RESULT_HIDDEN) {
					toggleSoftInput();
				}
			}
		});
	}

	/**
	 * Hide the soft input.
	 *
	 * @param activity The activity.
	 */
	public static void hideSoftInput(final Activity activity) {
		View view = activity.getCurrentFocus();
		if (view == null) {
			view = new View(activity);
		}
		hideSoftInput(view);
	}

	/**
	 * Hide the soft input.
	 *
	 * @param view The view.
	 */
	public static void hideSoftInput(final View view) {
		InputMethodManager imm =
				(InputMethodManager) AppConfig.INSTANCE.getApplication().getSystemService(Context.INPUT_METHOD_SERVICE);
		if (imm == null) return;
		imm.hideSoftInputFromWindow(view.getWindowToken(), 0, new ResultReceiver(new Handler()) {
			@Override
			protected void onReceiveResult(int resultCode, Bundle resultData) {
				if (resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN
						|| resultCode == InputMethodManager.RESULT_SHOWN) {
					toggleSoftInput();
				}
			}
		});
	}

	/**
	 * Toggle the soft input display or not.
	 */
	public static void toggleSoftInput() {
		InputMethodManager imm =
				(InputMethodManager) AppConfig.INSTANCE.getApplication().getSystemService(Context.INPUT_METHOD_SERVICE);
		//noinspection ConstantConditions
		imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
	}

	/**
	 * Return whether soft input is visible.
	 *
	 * @param activity The activity.
	 * @return {@code true}: yes<br>{@code false}: no
	 */
	public static boolean isSoftInputVisible(final Activity activity) {
		return getDecorViewInvisibleHeight(activity) > 0;
	}

	private static int sDecorViewDelta = 0;

	private static int getDecorViewInvisibleHeight(final Activity activity) {
		final View decorView = activity.getWindow().getDecorView();
		if (decorView == null) return sDecorViewInvisibleHeightPre;
		final Rect outRect = new Rect();
		decorView.getWindowVisibleDisplayFrame(outRect);
		Log.d("KeyboardUtils", "getDecorViewInvisibleHeight: "
				+ (decorView.getBottom() - outRect.bottom));
		int delta = Math.abs(decorView.getBottom() - outRect.bottom);
		if (delta <= getNavBarHeight()) {
			sDecorViewDelta = delta;
			return 0;
		}
		return delta - sDecorViewDelta;
	}

	/**
	 * Register soft input changed listener.
	 *
	 * @param activity The activity.
	 * @param listener The soft input changed listener.
	 */
	public static void registerSoftInputChangedListener(final Activity activity, final OnSoftInputChangedListener listener) {
		final int flags = activity.getWindow().getAttributes().flags;
		if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {
			activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
		}
		final FrameLayout contentView = activity.findViewById(android.R.id.content);
		sDecorViewInvisibleHeightPre = getDecorViewInvisibleHeight(activity);
		onSoftInputChangedListener = listener;
		onGlobalLayoutListener = new OnGlobalLayoutListener() {
			@Override
			public void onGlobalLayout() {
				if (onSoftInputChangedListener != null) {
					int height = getDecorViewInvisibleHeight(activity);
					if (sDecorViewInvisibleHeightPre != height) {
						onSoftInputChangedListener.onSoftInputChanged(height);
						sDecorViewInvisibleHeightPre = height;
					}
				}
			}
		};
		contentView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
	}

	/**
	 * Unregister soft input changed listener.
	 *
	 * @param activity The activity.
	 */
	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	public static void unregisterSoftInputChangedListener(final Activity activity) {
		final View contentView = activity.findViewById(android.R.id.content);
		contentView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
		onSoftInputChangedListener = null;
		onGlobalLayoutListener = null;
	}

	/**
	 * Fix the bug of 5497 in Android.
	 * <p>Don't set adjustResize 软键盘遮盖问题</p>
	 *
	 * @param activity The activity.
	 */
	public static void fixAndroidBug5497(final Activity activity) {
//        Window window = activity.getWindow();
//        int softInputMode = window.getAttributes().softInputMode;
//        window.setSoftInputMode(softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
		final FrameLayout contentView = activity.findViewById(android.R.id.content);
		final View contentViewChild = contentView.getChildAt(0);
		final int paddingBottom = contentViewChild.getPaddingBottom();
		sContentViewInvisibleHeightPre5497 = getContentViewInvisibleHeight(activity);
		contentView.getViewTreeObserver()
				.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
					@Override
					public void onGlobalLayout() {
						int height = getContentViewInvisibleHeight(activity);
						if (sContentViewInvisibleHeightPre5497 != height) {
							contentViewChild.setPadding(
									contentViewChild.getPaddingLeft(),
									contentViewChild.getPaddingTop(),
									contentViewChild.getPaddingRight(),
									paddingBottom + getDecorViewInvisibleHeight(activity)
							);
							sContentViewInvisibleHeightPre5497 = height;
						}
					}
				});
	}

	private static int getContentViewInvisibleHeight(final Activity activity) {
		final View contentView = activity.findViewById(android.R.id.content);
		if (contentView == null) return sContentViewInvisibleHeightPre5497;
		final Rect outRect = new Rect();
		contentView.getWindowVisibleDisplayFrame(outRect);
		Log.d("KeyboardUtils", "getContentViewInvisibleHeight: "
				+ (contentView.getBottom() - outRect.bottom));
		int delta = Math.abs(contentView.getBottom() - outRect.bottom);
		if (delta <= getStatusBarHeight() + getNavBarHeight()) {
			return 0;
		}
		return delta;
	}

	/**
	 * Fix the leaks of soft input.
	 * <p>Call the function in {@link Activity #onDestroy()}.</p>
	 *
	 * @param activity The activity.
	 */
	public static void fixSoftInputLeaks(final Activity activity) {
		if (activity == null) return;
		InputMethodManager imm =
				(InputMethodManager) AppConfig.INSTANCE.getApplication().getSystemService(Context.INPUT_METHOD_SERVICE);
		if (imm == null) return;
		String[] leakViews = new String[]{"mLastSrvView", "mCurRootView", "mServedView", "mNextServedView"};
		for (String leakView : leakViews) {
			try {
				Field leakViewField = InputMethodManager.class.getDeclaredField(leakView);
				if (leakViewField == null) continue;
				if (!leakViewField.isAccessible()) {
					leakViewField.setAccessible(true);
				}
				Object obj = leakViewField.get(imm);
				if (!(obj instanceof View)) continue;
				View view = (View) obj;
				if (view.getRootView() == activity.getWindow().getDecorView().getRootView()) {
					leakViewField.set(imm, null);
				}
			} catch (Throwable ignore) { /**/ }
		}
	}

	/**
	 * Click blank area to hide soft input.
	 * <p>Copy the following code in ur activity.</p>
	 */
	public static void clickBlankArea2HideSoftInput() {
		Log.i("KeyboardUtils", "Please refer to the following code.");
        /*@Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                View v = getCurrentFocus();
                if (isShouldHideKeyboard(v, ev)) {
                    InputMethodManager imm =
                            (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(),
                            InputMethodManager.HIDE_NOT_ALWAYS
                    );
                }
            }
            return super.dispatchTouchEvent(ev);
        }

        // Return whether touch the view.
        private boolean isShouldHideKeyboard(View v, MotionEvent event) {
            if (v != null && (v instanceof EditText)) {
                int[] l = {0, 0};
                v.getLocationInWindow(l);
                int left = l[0],
                        top = l[1],
                        bottom = top + v.getHeight(),
                        right = left + v.getWidth();
                return !(event.getX() > left && event.getX() < right
                        && event.getY() > top && event.getY() < bottom);
            }
            return false;
        }*/
	}

	private static int getStatusBarHeight() {
		Resources resources = Resources.getSystem();
		int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
		return resources.getDimensionPixelSize(resourceId);
	}

	private static int getNavBarHeight() {
		Resources res = Resources.getSystem();
		int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
		if (resourceId != 0) {
			return res.getDimensionPixelSize(resourceId);
		} else {
			return 0;
		}
	}
	///////////////////////////////////////////////////////////////////////////
	// interface
	///////////////////////////////////////////////////////////////////////////

	public interface OnSoftInputChangedListener {
		void onSoftInputChanged(int height);
	}
	///////////////////////////////////////////////////////////////////////////
	// 额外加的方法
	///////////////////////////////////////////////////////////////////////////

	/**
	 * 禁用软键盘，
	 *
	 * @param edtPassword
	 * @param activity
	 */
	public static void forbiddenSystemKeyboard(EditText edtPassword, Activity activity) {
		//设置不调用系统键盘
		if (Build.VERSION.SDK_INT <= 10) {
			edtPassword.setInputType(InputType.TYPE_NULL);
		} else {
			//activity.getWindow().setSoftInputMode(
			//		WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
			try {
				Class<EditText> cls = EditText.class;
				Method setShowSoftInputOnFocus;
				setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
				setShowSoftInputOnFocus.setAccessible(true);
				setShowSoftInputOnFocus.invoke(edtPassword, false);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 关闭软键盘
	 *
	 * @param view
	 */
	public static void hideKeyboard(View view) {
		InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
		imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
	}

	/**
	 * 显示键盘
	 *
	 * @param view
	 */
	public static void showKeyboard(View view, ResultReceiver resultReceiver) {
		InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
		if (imm != null) {
			view.requestFocus();
			//判断回调是否为null，不为空用有回调的方法
			if (resultReceiver != null) {
				imm.showSoftInput(view, 0,resultReceiver);
			} else {
				imm.showSoftInput(view, 0);
			}
		}
	}

	/**
	 * 延迟 100 毫秒 开启键盘，用于从 Dialog 回调到具体界面，键盘不会立刻弹出的情况
	 * @param view EditText
	 */
	public static void showKeyBoardDelay(final View view,ResultReceiver resultReceiver) {
		Timer timer = new Timer();
		view.requestFocus();
		view.requestFocusFromTouch();
		timer.schedule(new TimerTask() {
			public void run() {
				InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
				//判断回调是否为null，不为空用有回调的方法
				if (resultReceiver == null) {
					inputManager.showSoftInput(view, 0);
				} else {
					inputManager.showSoftInput(view, 0,resultReceiver);
				}

			}
		}, 300);// 300毫秒后自动弹出  原来是100 有时候也不弹出
	}
	//判断键盘是否已经弹出来
	public static boolean isSHowKeyboard(Context context, View v) {
		InputMethodManager imm = (InputMethodManager) context.getSystemService(context.INPUT_METHOD_SERVICE);
		if (imm.hideSoftInputFromWindow(v.getWindowToken(), 0)) {
			imm.showSoftInput(v, 0);
			return true;
			//软键盘已弹出
		} else {
			return false;
			//软键盘未弹出
		}
	}

	/**
	 * EditText获取焦点并显示软键盘
	 */
	public static void showSoftInputFromWindow(EditText editText) {
		editText.setFocusable(true);
		editText.setFocusableInTouchMode(true);
		editText.requestFocus();
		//activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
	}
}





























